%{
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <sstream>

#include <cstring>
#include <string>
#include <map>
#include <stack>
#include <fstream>
#include <cmath>

#include "drzewo.h"

bool debug = true;

using namespace std;

// stuff from flex that bison needs to know about:
extern "C" int yylex();
extern "C" int yyparse();
extern "C" FILE *yyin;

struct StrukturaZmiennych
{
	string 	typ;
	float 	fval;
	string 	sval;
};

stack <float> 						stos_wartosci;
map <string, StrukturaZmiennych> 	mapa_zmiennych;
map<string, Drzewo*>				mapa_jump;


int yylex(void);
int yyerror(const char * s);
Drzewo *poczatek;

string n2s(float tmp)
{
	stringstream ss;
	ss << tmp;
	return ss.str();
}

float s2n(string str)
{
	stringstream ss;
	ss << str;
	float k;
	ss >> k;
	return k;
}

bool s2b(string str)
{
	if(str == "false" || str == "" || str == "0" || str == "0.0")
		return false;
	else
		return true;
}

void ustaw_obecnego(Drzewo	*obecny, string wc="")
{
	if(debug) cout << wc << "ustaw obecnego - prawy:" << obecny->prawy->wartosc << "  lewy:" << obecny->wartosc << endl;
	string typ = mapa_zmiennych[obecny->wartosc].typ;
	
	if((obecny->prawy->d_typ_dzilania == "string" && typ!="string") || (obecny->prawy->d_typ_dzilania != "string" && typ=="string"))
	{
		if(debug) cout << "niewlasciwe przypisanie do zmiennej : " << obecny->wartosc << endl;	
		exit(-1);
	}
	
	if(typ == "int")
	{
		mapa_zmiennych[obecny->wartosc].fval = round(s2n(obecny->prawy->wartosc));
	}
	else if(typ == "float")
	{
		mapa_zmiennych[obecny->wartosc].fval = s2n(obecny->prawy->wartosc);
	}
	else if(typ == "bool")
	{
		mapa_zmiennych[obecny->wartosc].fval = s2b(obecny->prawy->wartosc);
	}
	else if(typ == "string")
	{
		mapa_zmiennych[obecny->wartosc].sval = obecny->prawy->wartosc;
	}
}

Drzewo* rozwiaz_drzewo(Drzewo *obecny,string wc="")
{
	wc+=" |";
	if(obecny == 0 || obecny->prawy == 0)
		return 0;

	if(obecny->d_typ_dzilania == "set")
	{
		if(debug) cout << wc  << " set " << endl;
		ustaw_obecnego(obecny,wc);
	}
	///////////////////////////////////////
	else if(obecny->d_typ_dzilania == "push")
	{
		if(debug) cout << wc  << obecny->d_typ_dzilania << endl;
		if(obecny->prawy->d_typ_dzilania == "id")
			obecny->wartosc = n2s(mapa_zmiennych[obecny->prawy->wartosc].fval);
		else
			obecny->wartosc = obecny->prawy->wartosc;		
			
		if(debug) cout << wc  << " wartosc z push : " << obecny->wartosc << endl;
	}	
	///////////////////////////////////////
	else if(obecny->d_typ_dzilania == "krok")
	{
		if(debug) cout << wc  << obecny->d_typ_dzilania  << endl;
		Drzewo* rtmp = rozwiaz_drzewo(obecny->prawy,wc);
		if( rtmp !=0 && rtmp !=obecny->lewy )
				return rtmp;
		if(debug) cout << wc  << "obency prawy wartosc w krok :" << obecny->prawy->wartosc << endl;
		if(obecny->lewy != 0)		
		{
			if(debug) cout << wc  << "obecy lewy != 0" << endl;
			if(obecny->lewy->d_typ_dzilania != "retval")
			{
//				if(debug) cout << wc  << obecny->lewy->d_typ_dzilania << endl;
				Drzewo* ltmp = rozwiaz_drzewo(obecny->lewy,wc);
				if( ltmp !=0 && ltmp !=obecny->lewy )
					return ltmp;
			}
			else
			{
				if(debug) cout << wc  << " !! retval " << obecny->d_typ_dzilania << endl;
				if(debug) cout << wc  << "lewa : " << obecny->lewy->wartosc << " | " << obecny->prawy->wartosc << endl;
				obecny->wartosc = obecny->lewy->wartosc;
				ustaw_obecnego(obecny,wc);
			}	
			
			if(obecny->lewy->d_typ_dzilania == "add")
			{
				if(debug) cout << wc  << obecny->lewy->d_typ_dzilania << endl;
				obecny->wartosc = n2s(s2n(obecny->prawy->wartosc) + s2n(obecny->lewy->wartosc));
				if(debug) cout << wc  <<  "\tadd  wartosc : " << obecny->wartosc << endl;
			}
			else if(obecny->lewy->d_typ_dzilania == "subs")
			{
				if(debug) cout << wc  << obecny->lewy->d_typ_dzilania << endl;
				obecny->wartosc = n2s(s2n(obecny->prawy->wartosc) - s2n(obecny->lewy->wartosc));
				if(debug) cout << wc  <<  "\tadd  wartosc : " << obecny->wartosc << endl;
			}
			else if(obecny->lewy->d_typ_dzilania == "multi")
			{
				if(debug) cout << wc  << obecny->lewy->d_typ_dzilania << endl;
				obecny->wartosc = n2s(s2n(obecny->prawy->wartosc) * s2n(obecny->lewy->wartosc));
				if(debug) cout << wc  <<  "\tadd  wartosc : " << obecny->wartosc << endl;
			}
			else if(obecny->lewy->d_typ_dzilania == "div")
			{
				if(debug) cout << wc  << obecny->lewy->d_typ_dzilania << endl;
				if(s2n(obecny->lewy->wartosc)==0)
				{
					if(debug) cout << "Nie dziel przez 0 !!" << endl;
					exit(-2);
				}
				obecny->wartosc = n2s(s2n(obecny->prawy->wartosc) / s2n(obecny->lewy->wartosc));
				if(debug) cout << wc  <<  "\tadd  wartosc : " << obecny->wartosc << endl;
			}
			else if(obecny->lewy->d_typ_dzilania == "eql")
			{
				if(debug) cout << wc  << obecny->lewy->d_typ_dzilania << endl;
				obecny->wartosc = n2s(s2n(obecny->prawy->wartosc) == s2n(obecny->lewy->wartosc));
				if(debug) cout << wc  <<  "\tadd  wartosc : " << obecny->wartosc << endl;
			}
			else if(obecny->lewy->d_typ_dzilania == "neql")
			{
				if(debug) cout << wc  << obecny->lewy->d_typ_dzilania << endl;
				obecny->wartosc = n2s(s2n(obecny->prawy->wartosc) != s2n(obecny->lewy->wartosc));
				if(debug) cout << wc  <<  "\tadd  wartosc : " << obecny->wartosc << endl;
			}
			else if(obecny->lewy->d_typ_dzilania == "cmp")
			{
				if(debug) cout << wc  << obecny->lewy->d_typ_dzilania << endl;
				obecny->wartosc = n2s(s2n(obecny->prawy->wartosc) > s2n(obecny->lewy->wartosc));
				if(debug) cout << wc  <<  "\tadd  wartosc : " << obecny->wartosc << endl;
			}			
			else if(obecny->lewy->d_typ_dzilania == "ncmp")
			{
				if(debug) cout << wc  << obecny->lewy->d_typ_dzilania << endl;
				obecny->wartosc = n2s(s2n(obecny->prawy->wartosc) < s2n(obecny->lewy->wartosc));
				if(debug) cout << wc  <<  "\tadd  wartosc : " << obecny->wartosc << endl;
			}
			else if(obecny->lewy->d_typ_dzilania == "leql")
			{
				if(debug) cout << wc  << obecny->lewy->d_typ_dzilania << endl;
				obecny->wartosc = n2s(s2n(obecny->prawy->wartosc) <= s2n(obecny->lewy->wartosc));
				if(debug) cout << wc  <<  "\tadd  wartosc : " << obecny->wartosc << endl;
			}			
			else if(obecny->lewy->d_typ_dzilania == "geql")
			{
				if(debug) cout << wc  << obecny->lewy->d_typ_dzilania << endl;
				obecny->wartosc = n2s(s2n(obecny->prawy->wartosc) >= s2n(obecny->lewy->wartosc));
				if(debug) cout << wc  <<  "\tadd  wartosc : " << obecny->wartosc << endl;
			}			
			else if(obecny->lewy->d_typ_dzilania == "push")
			{
				obecny->wartosc = obecny->lewy->wartosc; 
			}
			else if(obecny->lewy->d_typ_dzilania == "jump")
			{
				rozwiaz_drzewo(obecny->lewy->warunek);
				
				bool r = false;
				if(mapa_zmiennych.find(obecny->lewy->warunek->wartosc) != mapa_zmiennych.end())
					r=s2b(n2s(mapa_zmiennych[obecny->lewy->warunek->wartosc].fval));
				else
					r=s2b(obecny->lewy->warunek->wartosc);
					
				if(r)
				{
					if(debug) cout << wc  << "+ + +"<< obecny->lewy->d_typ_dzilania << "++ obecny wartosc:" << obecny->wartosc << " || " << obecny->lewy->warunek->wartosc << endl;
					rozwiaz_drzewo(mapa_jump[obecny->lewy->wartosc],wc);
					//exit(-1);
					return mapa_jump[obecny->lewy->wartosc];
				}
			}
			else if(obecny->lewy->d_typ_dzilania == "print")
			{
				rozwiaz_drzewo(obecny->lewy->warunek,wc);
				//if(debug) cout << "??? " << obecny->lewy->warunek->wartosc << endl;
				if(mapa_zmiennych[obecny->lewy->warunek->wartosc].typ == "string")
					cout << mapa_zmiennych[obecny->lewy->warunek->wartosc].sval << endl;
				else
					cout << mapa_zmiennych[obecny->lewy->warunek->wartosc].fval << endl;
			}
			else
			{
				obecny->wartosc = obecny->prawy->wartosc;
			}
		}
		else
		{
			obecny->wartosc =  obecny->prawy->wartosc;
		}
	}
	///////////////////////////////////////
	else if(obecny->d_typ_dzilania == "etykieta")
	{
		if(debug) cout << wc  << obecny->d_typ_dzilania << endl;
		rozwiaz_drzewo(obecny->prawy,wc);
	}
	///////////////////////////////////////
	else if(obecny->d_typ_dzilania == "jump")
	{
		if(debug) cout << wc  << "+ +"<< obecny->d_typ_dzilania << "++ obecny wartosc:" << obecny->wartosc << endl;
		rozwiaz_drzewo(mapa_jump[obecny->wartosc],wc);
	}
	///////////////////////////////////////
	else if(obecny->d_typ_dzilania == "add" || obecny->d_typ_dzilania == "subs" || obecny->d_typ_dzilania == "multi" || obecny->d_typ_dzilania == "div")
	{
		if(debug) cout << wc  << "ustawienie dla :" << obecny->d_typ_dzilania << endl;
		rozwiaz_drzewo(obecny->prawy,wc);
		if(obecny->prawy->d_typ_dzilania == "id")
			obecny->wartosc = n2s(mapa_zmiennych[obecny->prawy->wartosc].fval);
		else
			obecny->wartosc = obecny->prawy->wartosc;	
		if(debug) cout << wc  << "dzialanie :" << obecny->wartosc << endl;
	}
	return 0;
}


%}

%token <strval> 	BOOL
%token <strval> 	FLOAT
%token <strval> 	INT
%token <strval> 	STRING
%token <strval> 	ETYKIETA
%token <strval> 	ID_ZMIENNEJ
%token <strval>		TYP_INT 
%token <strval>		TYP_FLOAT 
%token <strval>		TYP_BOOL 
%token <strval>		TYP_STRING
%token <strval> 	SET PUSH
%token <strval>  	ADD SUBS MULTI DIV
%token <strval>		RETVAL
%token <strval>		JMPIF
%token <strval>		EQL NEQL CMP LEQL GEQL
%token <strval>		PRINT
%token <strval>		END_OF_LINE
%token <strval>		PRZECINEK

%%

_main_: glowny_program 
		{
			poczatek = $<drzewoval>1;
		}
;

glowny_program:	glowny_program pod_program
		{
			Drzewo *d = new Drzewo;
			d->d_typ_dzilania 	= "krok";
			d->prawy 			= $<drzewoval>1;
			d->lewy				= $<drzewoval>2;
			$<drzewoval>$		= d;
		}	 
	| pod_program
		{
			Drzewo *d = new Drzewo;
			d->d_typ_dzilania 	= "krok";
			d->prawy 			= $<drzewoval>1;
			d->lewy				= 0;
			$<drzewoval>$		= d;
		}	
;

pod_program : ETYKIETA wykonanie
		{
			Drzewo *d = new Drzewo;
			mapa_jump[$<strval>1] = d;
			d->d_typ_dzilania = "etykieta";
			d->prawy = $<drzewoval>2 ;
			$<drzewoval>$	=	d;
//			if(debug) cout << $1 << endl;
		}
;

wykonanie: wykonanie operacje
		{
			Drzewo *d = new Drzewo;
			d->d_typ_dzilania 	= "krok";
			d->prawy 			= $<drzewoval>1;
			d->lewy				= $<drzewoval>2;
			$<drzewoval>$		= d;
		}	 
	| operacje 
		{
			Drzewo *d = new Drzewo;
			d->d_typ_dzilania 	= "krok";
			d->prawy 			= $<drzewoval>1;
			d->lewy				= 0;
			$<drzewoval>$		= d;
		}
;

set_retval:	SET ID_ZMIENNEJ PRZECINEK RETVAL
	{
		Drzewo *d 			= new Drzewo;
		d->wartosc 			= $<strval>2;
		d->d_typ_dzilania 	= "retval";
		$<drzewoval>$ 		= d;
	}
;

operacje: operacje_na_zmiennych 	{ $<drzewoval>$ = $<drzewoval>1;}
	| push							{ $<drzewoval>$ = $<drzewoval>1;}
	| dzialania						{ $<drzewoval>$ = $<drzewoval>1;}
	| jump							{ $<drzewoval>$ = $<drzewoval>1;}
	| set_retval					{ $<drzewoval>$ = $<drzewoval>1;}
	| PRINT	wprowadzona_zmienna
	{
		Drzewo* d 			= new Drzewo;
		d->d_typ_dzilania 	= "print";
		d->warunek			= $<drzewoval>2;
		//if(debug) cout << "print: " << d->warunek->wartosc << endl;
		$<drzewoval>$ 		= d;
	}
;

jump:	JMPIF wprowadzona_zmienna PRZECINEK ETYKIETA 
	{ 
		Drzewo* d 				= new Drzewo;
		d->d_typ_dzilania  		= "jump";
		d->wartosc				= $<strval>4;
		d->warunek				= $<drzewoval>2;
		$<drzewoval>$ 			= d;

		//if(debug) cout << $<strval>2 << " " << $<strval>3 << " " << $<strval>4 << endl;
	}
; 

dzialania: typ_dzialania 		wprowadzona_zmienna
		{
			Drzewo *d 			= new Drzewo;
			d->d_typ_dzilania 	= $<strval>1;
			d->prawy 			= $<drzewoval>2;
			$<drzewoval>$		= d;
			
			//if(debug) cout << $<strval>1 << " " << $<strval>2 << endl;
		}
	|  typ_porownania wprowadzona_zmienna PRZECINEK wprowadzona_zmienna
		{
			Drzewo *d 			= new Drzewo;
			d->d_typ_dzilania 	= $<strval>1;
			d->prawy 			= $<drzewoval>2;
			d->lewy				= $<drzewoval>4;
			$<drzewoval>$		= d;
		}
;

typ_porownania:	EQL 	{ $<strval>$ = $<strval>1; }
	| NEQL				{ $<strval>$ = $<strval>1; }
	| CMP				{ $<strval>$ = $<strval>1; }
	| LEQL				{ $<strval>$ = $<strval>1; }
	| GEQL				{ $<strval>$ = $<strval>1; }
;

push:	PUSH 		wprowadzona_zmienna 
		{ 
			Drzewo *d 			= new Drzewo;
			d->d_typ_dzilania 	= "push";
			d->prawy 			= $<drzewoval>2;
			$<drzewoval>$		= d;
			//if(debug) cout << $<strval>1 << " " << $<strval>2 << endl;
		}
;

operacje_na_zmiennych: typ_deklarowany ID_ZMIENNEJ 
	{
		//Drzewo *d = new Drzewo;	d->d_typ_dzilania = $<strval>1; d->wartosc = $<strval>2;
		$<drzewoval>$ = 0;
		StrukturaZmiennych k;
		k.typ = $<strval>1;
		k.sval = "";
		k.fval = 0.0;
		mapa_zmiennych[$<strval>2] = k;
	}
	| SET ID_ZMIENNEJ PRZECINEK wprowadzona_zmienna
	{
		Drzewo *d 	= new Drzewo; 
		d->wartosc 	= $<strval>2;
		d->prawy 	= $<drzewoval>4;
		d->d_typ_dzilania = "set";
		$<drzewoval>$ = d;
	}
;

typ_dzialania: ADD 				{ $<strval>$ = $<strval>1; }
	| SUBS 						{ $<strval>$ = $<strval>1; }
	| MULTI 					{ $<strval>$ = $<strval>1; }
	| DIV 						{ $<strval>$ = $<strval>1; }
;

wprowadzona_zmienna: INT 
		{ 
			Drzewo *d 			= new Drzewo;
			d->wartosc 			= $<strval>1;
			d->d_typ_dzilania 	= "int";
			$<drzewoval>$	 	= d; 
		}
	| FLOAT
		{ 
			Drzewo *d 		= new Drzewo;
			d->wartosc 		= $<strval>1;
			d->d_typ_dzilania 			= "float";
			$<drzewoval>$ 	= d; 
		}
	| BOOL
		{ 
			Drzewo *d 		= new Drzewo;
			d->wartosc 		= $<strval>1;
			d->d_typ_dzilania 			= "bool";
			$<drzewoval>$ 	= d; 
		}	
	| STRING
		{ 
			Drzewo *d 		= new Drzewo;
			d->wartosc 		= $<strval>1;
			d->d_typ_dzilania 			= "string";
			$<drzewoval>$ 	= d; 
		}
	| ID_ZMIENNEJ
		{ 
			Drzewo *d 		= new Drzewo;
			d->wartosc 		= $<strval>1;
			d->d_typ_dzilania 			= "id";
			$<drzewoval>$ 	= d; 
		}
;

typ_deklarowany:	TYP_BOOL 		{ $<strval>$ = $<strval>1; }
	| TYP_FLOAT 					{ $<strval>$ = $<strval>1; }
	| TYP_INT 						{ $<strval>$ = $<strval>1; }
	| TYP_STRING 					{ $<strval>$ = $<strval>1; }
;

%%
#include "lex.yy.cc"
ifstream infile;

int yyerror(const char *s) {
	printf("\nBlad: %s\n", s);
	exit(1);
}

int main(int argc, char** argv){
	//if(argc>1)
		debug = true;
	infile.open("tmp.txt");
	yyparse();
	if(debug) cout << "start" << endl;
	rozwiaz_drzewo(poczatek);
	
	if(debug) cout << " - - - - - " << endl;
	map<string, StrukturaZmiennych>::iterator it = mapa_zmiennych.begin();
	for(;it!=mapa_zmiennych.end();++it)
	{
		if(debug) cout << "zmienna : " << it->first << " " 
				<< (*it).second.fval << " "
				<< (*it).second.sval << endl;
	}
	infile.close();
	return 0;
}
int yylex(void){
	static FlexLexer* lexer = new yyFlexLexer(&infile);
	lexer->yylex();
}